﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;

namespace AL.Extension
{
    /// <summary>
    /// HH: 排序类型（0：升序 1：降序）
    /// </summary>
    public enum OrderByType
    {
        /// <summary>
        /// HH: 升序排列
        /// </summary>
        Asc = 0,

        /// <summary>
        /// HH: 降序排列
        /// </summary>
        Desc = 1
    }


    public static class ExtensionT
    {

        #region Lambda 表达式扩展

        /// <summary>
        /// HH: 根据对象属性的字符串名称 生成 Lambda 排序查询（Asc）
        /// </summary>
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> queryable, string propertyName)
        {
            return OrderBy(queryable, propertyName, OrderByType.Asc);
        }

        /// <summary>
        /// HH: 根据对象属性的字符串名称 生成 Lambda 排序查询（可选升序/降序）
        /// </summary>
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> queryable, string propertyName, OrderByType orderByType)
        {
            var param = Expression.Parameter(typeof(T));
            var body = Expression.Property(param, propertyName);
            dynamic keySelector = Expression.Lambda(body, param);
            return (orderByType == OrderByType.Desc) ? Queryable.OrderByDescending(queryable, keySelector) : Queryable.OrderBy(queryable, keySelector);
        }

        /// <summary>
        /// HH: 为 IQueryable 扩展 WhereIn 方法
        /// </summary>
        public static IQueryable<TElement> WhereIn<TElement, TValue>(this IQueryable<TElement> source, Expression<Func<TElement, TValue>> propertySelector, params TValue[] values)
        {
            return source.Where(BuildWhereInExpression(propertySelector, values));

            // 调用演示
            // string[] ids = new string[] { 10101, 10005, 10007 };
            // db.Profile.WhereIn(c => c.Id, ids);

            // Entity SQL 调用演示
            //string[] ids = new string[]{10101,10005,10007}；
            //string csvIds = string.Join(",", ids.Cast<string>().ToArray());
            //db.Profile.Where("it.Id in {"+csvIds+"}");
        }

        /// <summary>
        /// HH: Lambda 表达式 扩展 Where In
        /// </summary>
        private static Expression<Func<TElement, bool>> BuildWhereInExpression<TElement, TValue>(Expression<Func<TElement, TValue>> propertySelector, IEnumerable<TValue> values)
        {
            ParameterExpression p = propertySelector.Parameters.Single();
            if (!values.Any())
                return e => false;

            var equals = values.Select(value => (Expression)Expression.Equal(propertySelector.Body, Expression.Constant(value, typeof(TValue))));
            var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));

            return Expression.Lambda<Func<TElement, bool>>(body, p);

            // 调用演示
            // int[] ids = new int[]{10101,10005,10007};
            // db.Profile.Where(BuildWhereInExpression<Profile,int>(v=>v.Id,ids);
        }

        #endregion


        #region T 扩展

        /// <summary>
        /// HH: 判断 泛类型对象 是否为 null 或者字符串空
        /// </summary>
        public static bool IsNullOrEmpty<T>(this T data)
        {
            //如果为null
            if (data == null) return true;

            //如果为""
            if (data.GetType() == typeof(String))
            {
                if (string.IsNullOrEmpty(data.ToString().Trim()) || data.ToString() == "") return true;
            }

            //如果为DBNull
            if (data.GetType() == typeof(DBNull)) return true;

            //不为空
            return false;
        }

        #endregion


        #region object 扩展

        public static object HH_ChanageType(this object value, Type convertsionType)
        {
            //判断convertsionType类型是否为泛型，因为nullable是泛型类,
            if (convertsionType.IsGenericType &&
                //判断convertsionType是否为nullable泛型类
                convertsionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null || value.ToString().Length == 0)
                {
                    return null;
                }

                //如果convertsionType为nullable类，声明一个NullableConverter类，该类提供从Nullable类到基础基元类型的转换
                var nullableConverter = new NullableConverter(convertsionType);
                //将convertsionType转换为nullable对的基础基元类型
                convertsionType = nullableConverter.UnderlyingType;
            }
            var r = Convert.ChangeType(value, convertsionType);
            return r;
        }

        /// <summary>
        /// HH: 判断 对象 是否为 Null 或者 字符串空
        /// </summary>
        /// <param name="data">要验证的对象</param>
        public static bool IsNullOrEmpty(this object data)
        {
            //如果为null
            if (data == null) return true;

            //如果为""
            if (data.GetType() == typeof(String))
            {
                if (string.IsNullOrEmpty(data.ToString().Trim())) return true;
            }

            //如果为DBNull
            if (data.GetType() == typeof(DBNull)) return true;

            //不为空
            return false;
        }

        ///// <summary>
        ///// HH: 判断一个数字类型是否包含指定值
        ///// </summary>
        //public static bool Contains(this object self, string data) {
        //    return self.ToString().Contains(data);
        //}

        #endregion


        #region string 扩展

        /// <summary>
        /// HH: 判断字符串是否为数字类型
        /// </summary>
        /// <param name="sNumeric"></param>
        /// <returns></returns>
        public static bool IsNumeric(this string sNumeric)
        {
            return (new Regex("^[\\+\\-]?[0-9]*\\.?[0-9]+$")).IsMatch(sNumeric);
        }

        /// <summary>
        /// HH: 判断 字符串 是否为 null 或者 字符串空
        /// </summary>
        public static bool IsNullOrEmpty(this string data)
        {
            return string.IsNullOrEmpty(data);
        }

        /// <summary>
        /// HH: 判断 字符串 是否为 Null 、字符串空 或者 仅由空白字符组成
        /// </summary>
        public static bool IsNullOrWhiteSpace(this string data)
        {
            return string.IsNullOrWhiteSpace(data);
        }

        ///// <summary>
        ///// HH: 判断一个数字类型是否包含指定值
        ///// </summary>
        //public static bool Contains(this string self, string data) {
        //    return self.ToString().Contains(data);
        //}

        #endregion


        #region Int64 扩展

        /// <summary>
        /// HH: 判断一个数字类型是否包含指定值
        /// </summary>
        public static bool Contains(Int64 self, string data)
        {
            return self.ToString().Contains(data);
        }

        #endregion

    }
}